package jsonm

import (
	"reflect"
	"strconv"
	"strings"
)

func isEmptyValue(i int ,v interface{}) bool {
	type_v := reflect.TypeOf(v)
	value_v := reflect.ValueOf(v)
	switch type_v.Field(i).Type.String() {
		case "bool":
			return value_v.Field(i).Bool() == false 
		case "int", "int8", "int16", "int32", "int64":			
			return value_v.Field(i).Int() == 0 
		case "uint", "uint8", "uint16", "uint32", "uint64":
			return value_v.Field(i).Uint() == 0
		case "float32":
			return value_v.Field(i).Float() == 0.0 
		case "float64":
			return value_v.Field(i).Float() == 0.0
		case "string":
			return value_v.Field(i).String() == "" 
		case "[]int", "[]float32", "[]float64", "[]string":			
			return value_v.Field(i).Len() == 0 
		case "map[int]int", "map[string]int", "map[string]interface {}":
			return value_v.Field(i).Len() == 0 
	}
	return true
}

func marshal(i int, v interface{},res string)string{
	type_v := reflect.TypeOf(v)
	value_v := reflect.ValueOf(v)
	switch type_v.Field(i).Type.String() {
		case "bool":
			res += dealbool(value_v.Field(i).Bool())
		case "int", "int8", "int16", "int32", "int64":
			res += strconv.FormatInt(value_v.Field(i).Int(), 10)
		case "uint", "uint8", "uint16", "uint32", "uint64":
			res += strconv.FormatUint(value_v.Field(i).Uint(), 10)
		case "float32":
			res += strconv.FormatFloat(value_v.Field(i).Float(), 'f', -1, 32)
		case "float64":
			res += strconv.FormatFloat(value_v.Field(i).Float(), 'f', -1, 64)
		case "string":
			res += "\"" + value_v.Field(i).String()+ "\""
		case "[]int":
			res += "[" + intslice(value_v.Field(i).Interface().([]int)) + "]"
		case "[]float32":
			res += "[" + float32slice(value_v.Field(i).Interface().([]float32)) + "]"
		case "[]float64":
			res += "[" + float64slice(value_v.Field(i).Interface().([]float64)) + "]"
		case "[]string":
			res += "[" + stringslice(value_v.Field(i).Interface().([]string)) + "]"
		case "map[int]int":
			res += "{" + mapintint(value_v.Field(i).Interface().(map[int]int)) + "}"
		case "map[string]int":
			res += "{" + mapstrint(value_v.Field(i).Interface().(map[string]int)) + "}"
		case "map[string]interface {}":
			res += "{" + mapstrinterface(value_v.Field(i).Interface().(map[string]interface{})) + "}"
		default:
			res += "unsupported type encoder:" + type_v.Field(i).Type.String()
	}
	return res
}


func dealbool(v bool) string {
	str := ""
	if v == true {
		str += "true"
	} else {
		str += "false"
	}
	return str
}

func intslice(v []int) string {
	res := ""
	for k := 0; k < len(v); k++ {
		res += strconv.Itoa(v[k])
		if k != len(v)-1 {
			res += ","
		}
	}
	return res
}

func float32slice(v []float32) string {
	res := ""
	for k := 0; k < len(v); k++ {
		res += strconv.FormatFloat(float64(v[k]), 'f', -1, 32)
		if k != len(v)-1 {
			res += ","
		}
	}
	return res
}

func float64slice(v []float64) string {
	res := ""
	for k := 0; k < len(v); k++ {
		res += strconv.FormatFloat(v[k], 'f', -1, 64)
		if k != len(v)-1 {
			res += ","
		}
	}
	return res
}

func stringslice(v []string) string {
	res := ""
	for k := 0; k < len(v); k++ {
		res += "\"" + v[k] + "\""
		if k != len(v)-1 {
			res += ","
		}
	}
	return res
}

func mapintint(v map[int]int) string {
	res := ""
	for i := range v {
		res += "\"" + strconv.FormatInt(int64(i), 10) + "\"" + ":"
		res += strconv.FormatInt(int64(v[i]), 10) + ","
	}
	res = res[:len(res)-1]
	return res
}

func mapstrint(v map[string]int) string {
	res := ""
	for i := range v {
		res += "\"" + i + "\"" + ":"
		res += strconv.FormatInt(int64(v[i]), 10) + ","
	}
	res = res[:len(res)-1]
	return res
}

func mapstrinterface(v map[string]interface{}) string {
	res := ""
	for i := range v {
		res += "\"" + i + "\"" + ":"
		switch v[i].(type) {
		case bool:
			if v[i] == true {
				res += "true"
			} else {
				res += "false"
			}
		case int:
			res += strconv.FormatInt(int64(v[i].(int)), 10)
		case string:
			res += "\"" + v[i].(string) + "\""
		}
		res += ","
	}
	res = res[:len(res)-1]
	return res
}

func JSONMarshal(v interface{}) ([]byte, error) {
	var res string = "{"
	type_v := reflect.TypeOf(v)
	for i := 0; i < type_v.NumField(); i++ {
		
		tagname := type_v.Field(i).Tag.Get("json")
		if tagname == "" {
			tagname = type_v.Field(i).Tag.Get("mytag")
		}
		
		if tagname == ""{
			res += "\"" + type_v.Field(i).Name + "\":"
		} else {
			if tagname == "-" {
				continue
			} else {
				if strings.Contains(tagname, ",") {
					name := ""
					tag := ""
					flag := 0
					for z := 0; z < len(tagname); z++ {
						if string(tagname[z]) == "," {
							flag = 1
							continue
						}
						if flag == 0 {
							name += string(tagname[z])
						} else {
							tag += string(tagname[z])
						}
					}
					if tag == "omitempty" {
						if isEmptyValue(i,v) {
							continue
						}
					}
					if name == "" {
						res += "\"" + type_v.Field(i).Name + "\":"
					} else {
						res += "\"" + name + "\":"
					}

				} else {
					res += "\"" + tagname + "\":"
				}
			}
		}
		
		res = marshal(i,v,res)
		if i != type_v.NumField()-1 {
			res += ","
		}
	}
	
	if string(res[len(res)-1]) == "," {
		res = res[:len(res)-1]
	}
	res += "}"
	var ret []byte = []byte(res)
	return ret, nil
}